﻿namespace Profit.Controls
{
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Globalization;
    using System.Linq;
    using System.Threading;
    using System.Threading.Tasks;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    using System.Windows.Input;
    using Converters;
    using Core.Contracts.Enums;
    using Core.Contracts.Interfaces;
    using Resources;
    using Services;

    /// <summary>
    /// Interaction logic for ItemsListControl.xaml
    /// </summary>
    public partial class ItemsListControl : UserControl
    {
        enum RobotViewLevel
        {
            Default = 0,
            Faction,
            Size
        }

        enum ModuleViewLevel
        {
            Default = 0,
            MetaGroup,
            Group,
            Size,
            None
        }

        /// <summary>
        /// Add module command handler
        /// </summary>
        public static DependencyProperty AddModuleCommandProperty = DependencyProperty.Register("AddModuleCommand", typeof(ICommand), typeof(ItemsListControl), new PropertyMetadata((ICommand)null));
        /// <summary>
        /// New Fitting Command handler
        /// </summary>
        public static DependencyProperty NewFittingCommandProperty = DependencyProperty.Register("NewFittingCommand", typeof(ICommand), typeof(ItemsListControl), new PropertyMetadata((ICommand)null));

        private GridViewColumnHeader _lastHeaderClicked;
        private ListSortDirection _lastDirection;
        private readonly GridView _modulesGridView;
        private readonly GridView _robotsGridView;
        private readonly ControlTemplate _robotTreeviewItemTemplate;
        private readonly ControlTemplate _moduleTreeviewItemTemplate;
        private readonly CollectionViewSource _robotsViewSource;
        private readonly CollectionViewSource _modulesViewSource;
        private RobotViewLevel _robotViewLevel;
        private ModuleViewLevel _moduleViewLevel;

        public ItemsListControl()
        {
            InitializeComponent();

            _robotsViewSource = new CollectionViewSource();
            _robotsViewSource.SortDescriptions.Add(new SortDescription() { PropertyName = "Size" });
            _robotsViewSource.SortDescriptions.Add(new SortDescription() { PropertyName = "Name" });
            _robotsViewSource.SortDescriptions.Add(new SortDescription() { PropertyName = "TechnologyLevel" });
            

            _modulesViewSource = new CollectionViewSource();
            _modulesViewSource.SortDescriptions.Add(new SortDescription() { PropertyName = "Size" });
            _modulesViewSource.SortDescriptions.Add(new SortDescription() { PropertyName = "TechnologyLevel" });


            _modulesGridView = FindResource("ModulesGridView") as GridView;
            _robotsGridView = FindResource("RobotsGridView") as GridView;
            _robotTreeviewItemTemplate = FindResource("RobotTreeviewItemTemplate") as ControlTemplate;
            _moduleTreeviewItemTemplate = FindResource("ModuleTreeviewItemTemplate") as ControlTemplate;

            itemsListview.GroupStyle.Add(FindResource("DefaultGroupStyle") as GroupStyle);

            InitializeRobotsTree();

            InitializeModulesTree();
        }

        /// <summary>
        /// Obtains or defines the AddModuleCommand handler
        /// </summary>
        public ICommand AddModuleCommand
        {
            get { return GetValue(AddModuleCommandProperty) as ICommand; }
            set { SetValue(AddModuleCommandProperty, value); }
        }
        /// <summary>
        /// Obtains or defines the NewFittingCommand handler
        /// </summary>
        public ICommand NewFittingCommand
        {
            get { return GetValue(NewFittingCommandProperty) as ICommand; }
            set { SetValue(NewFittingCommandProperty, value); }
        }

        private void InitializeRobotsTree()
        {
            var botsNode = new TreeViewItem() { Header = "Robots" };
            botsNode.Items.Add(string.Empty);
            botsNode.Selected += OnRobotsTreeViewItemSelected;
            botsNode.Expanded += OnRobotsTreeViewItemExpanded;
            botsNode.Collapsed += OnTreeViewItemCollapsed;
            
            itemsTreeView.Items.Add(botsNode);
        }

        private void InitializeModulesTree()
        {
            var modulesNode = new TreeViewItem() { Header = "Modules", Tag = "modules" };
            modulesNode.Items.Add(string.Empty);
            modulesNode.Selected += OnModulesTreeViewItemSelected;
            modulesNode.Expanded += OnModulesTreeViewItemExpanded;
            modulesNode.Collapsed += OnTreeViewItemCollapsed;

            itemsTreeView.Items.Add(modulesNode);
        }

        private void OnModulesTreeViewItemSelected(object sender, RoutedEventArgs e)
        {
            e.Handled = true;
            Task.Factory.StartNew(()=>SetModulesList(null));
        }

        private void OnModulesTreeViewItemExpanded(Object sender, RoutedEventArgs e )
        {
            e.Handled = true;
            var node = sender as TreeViewItem;
            if (node == null) return;
            
            Task.Factory.StartNew(()=>
                Dispatcher.Invoke(new ActionDelegate(() =>
                {
                    node.Items.Clear();
                    CreateMetagroupsItems(node, new ModuleMetagroupsToLabelConverter());
                })));
        }

        private void OnModuleMetagroupTreeViewItemExpanded(object sender, RoutedEventArgs e)
        {
            e.Handled = true;
            var node = sender as TreeViewItem;
            if(node == null) return;

            Task.Factory.StartNew(()=>
                Dispatcher.Invoke(new ActionDelegate(() =>
                {
                    node.Items.Clear();
                    CreateModuleGroupsItems(node, (ModuleMetaGroupsEnum)node.Tag, new ModuleGroupsToLabelConverter());
                })));
        }

        private void OnModuleMetagroupTreeViewItemSelected(object sender, RoutedEventArgs e)
        {
            e.Handled = true;
            var node = sender as TreeViewItem;
            if (node == null) return;

            _moduleViewLevel = ModuleViewLevel.MetaGroup;
            var meta = (ModuleMetaGroupsEnum) node.Tag;
            Task.Factory.StartNew(() => SetModulesList(Repository.Default.Modules.Where(m => m.MetaGroup == meta)));
        }

        private void OnModuleGroupTreeViewItemSelected(object sender, RoutedEventArgs e)
        {
            e.Handled = true;
            var node = sender as TreeViewItem;
            if (node == null) return;

            _moduleViewLevel = ModuleViewLevel.None;
            var meta = (ModuleMetaGroupsEnum) ((TreeViewItem) node.Parent).Tag;
            var group = (ModuleGroupsEnum) node.Tag;
            Task.Factory.StartNew(() => SetModulesList(Repository.Default.Modules.Where(m => m.MetaGroup == meta && m.Group == group)));
        }

        private void OnModuleGroupTreeViewItemExpanded(object sender, RoutedEventArgs e)
        {
            e.Handled = true;
            var node = sender as TreeViewItem;
            if(node ==null) return;

            Task.Factory.StartNew(()=>
                Dispatcher.Invoke(new ActionDelegate(() =>
                {
                    node.Items.Clear();
                    CreateModuleClassItems(node, (ModuleGroupsEnum)node.Tag);
                })));
        }

        private void OnModuleTreeViewItemSelected(object sender, RoutedEventArgs e)
        {
            e.Handled = true;
            var item = e.Source as TreeViewItem;
            if (item == null || item.Tag == null) return;
            
            _moduleViewLevel = ModuleViewLevel.None;
            var meta = (ModuleMetaGroupsEnum)((TreeViewItem)((TreeViewItem)item.Parent).Parent).Tag;
            var group = (ModuleGroupsEnum)((TreeViewItem)item.Parent).Tag;

            string xPath = string.Format("/modules/{0}/{1}/{2}/module", meta, group, item.Tag);
            Task.Factory.StartNew(() => SetModulesList(Repository.Default.LoadByPath<IModule>(xPath)));
        }

        private void OnModuleTreeViewItemExpanded(object sender, RoutedEventArgs e)
        {
            e.Handled = true;
            var node = sender as TreeViewItem;
            if(node ==null) return;

            Task.Factory.StartNew(()=>
                Dispatcher.Invoke(new ActionDelegate(() =>
                {
                    node.Items.Clear();
                    CreateModuleItems(node, (string)node.Tag);
                })));
        }

        private void CreateModuleItems(ItemsControl parent, string tag)
        {
            var meta = (ModuleMetaGroupsEnum)((TreeViewItem)((TreeViewItem)parent.Parent).Parent).Tag;
            var group = (ModuleGroupsEnum)((TreeViewItem)parent.Parent).Tag;

            string xpath = string.Format("/modules/{0}/{1}/{2}/module", meta, group, tag);

            Task.Factory.StartNew(()=>
                    Dispatcher.Invoke(new ActionDelegate(() =>
                    {
                        foreach (var module in Repository.Default.LoadByPath<IModule>(xpath))
                            parent.Items.Add(CreateModuleTreeViewItem(module));
                    })));
        }

        private void CreateMetagroupsItems(ItemsControl parent, IValueConverter labelConverter = null)
        {
            if (parent == null) return;

            parent.Items.Add(CreateModuleMetagroupItem(ModuleMetaGroupsEnum.Armor, labelConverter));
            parent.Items.Add(CreateModuleMetagroupItem(ModuleMetaGroupsEnum.ElectronicEquipment, labelConverter));
            parent.Items.Add(CreateModuleMetagroupItem(ModuleMetaGroupsEnum.ElectronicWarfare, labelConverter));
            parent.Items.Add(CreateModuleMetagroupItem(ModuleMetaGroupsEnum.EngineeringEquipment, labelConverter));
            parent.Items.Add(CreateModuleMetagroupItem(ModuleMetaGroupsEnum.Industrial, labelConverter));
            parent.Items.Add(CreateModuleMetagroupItem(ModuleMetaGroupsEnum.NexusModules, labelConverter));
            parent.Items.Add(CreateModuleMetagroupItem(ModuleMetaGroupsEnum.Shield, labelConverter));
            parent.Items.Add(CreateModuleMetagroupItem(ModuleMetaGroupsEnum.Weapons, labelConverter));
        }

        private TreeViewItem CreateModuleMetagroupItem(ModuleMetaGroupsEnum metaGroup, IValueConverter labelConverter = null )
        {
            var item = new TreeViewItem()
                           {
                               Header =
                                   labelConverter == null
                                       ? metaGroup
                                       : labelConverter.Convert(metaGroup, typeof (string), null, CultureInfo.CurrentCulture),
                               Tag = metaGroup
                           };


            item.Items.Add(string.Empty);
            item.Expanded += OnModuleMetagroupTreeViewItemExpanded;
            item.Selected += OnModuleMetagroupTreeViewItemSelected;
            item.Collapsed += OnTreeViewItemCollapsed;

            return item;
        }

        private TreeViewItem CreateModuleGroupItem(ModuleGroupsEnum group, IValueConverter labelConverter = null)
        {
            var item = new TreeViewItem()
                           {
                               Header =
                                   labelConverter == null
                                       ? group
                                       : labelConverter.Convert(group, typeof (string), null, CultureInfo.CurrentCulture),
                               Tag = group
                           };

            item.Items.Add(string.Empty);
            item.Selected += OnModuleGroupTreeViewItemSelected;
            item.Expanded += OnModuleGroupTreeViewItemExpanded;
            item.Collapsed += OnTreeViewItemCollapsed;

            return item;
        }

        private void CreateModuleGroupsItems(ItemsControl parent, ModuleMetaGroupsEnum metagroup, IValueConverter labelConverter = null)
        {
            if(parent ==null) return;
            switch (metagroup)
            {
                case ModuleMetaGroupsEnum.Armor :
                    parent.Items.Add(CreateModuleGroupItem(ModuleGroupsEnum.ArmorHardeners, labelConverter));
                    parent.Items.Add(CreateModuleGroupItem(ModuleGroupsEnum.ArmorPlates, labelConverter));
                    parent.Items.Add(CreateModuleGroupItem(ModuleGroupsEnum.ArmorRepairers, labelConverter));
                    parent.Items.Add(CreateModuleGroupItem(ModuleGroupsEnum.ArmorRepairersTunings, labelConverter));
                    parent.Items.Add(CreateModuleGroupItem(ModuleGroupsEnum.LightweightFrames, labelConverter));
                    parent.Items.Add(CreateModuleGroupItem(ModuleGroupsEnum.RemoteArmorRepairers, labelConverter));
                    break;
                case ModuleMetaGroupsEnum.ElectronicEquipment:
                    parent.Items.Add(CreateModuleGroupItem(ModuleGroupsEnum.CargoScanners, labelConverter));
                    parent.Items.Add(CreateModuleGroupItem(ModuleGroupsEnum.ChassisScanners, labelConverter));
                    parent.Items.Add(CreateModuleGroupItem(ModuleGroupsEnum.Coprocessors, labelConverter));
                    parent.Items.Add(CreateModuleGroupItem(ModuleGroupsEnum.RangeExtenders, labelConverter));
                    parent.Items.Add(CreateModuleGroupItem(ModuleGroupsEnum.RemoteSensorAmplifiers, labelConverter));
                    parent.Items.Add(CreateModuleGroupItem(ModuleGroupsEnum.SensorAmplifiers, labelConverter));
                    parent.Items.Add(CreateModuleGroupItem(ModuleGroupsEnum.SignalDetectors, labelConverter));
                    parent.Items.Add(CreateModuleGroupItem(ModuleGroupsEnum.SignalMaskers, labelConverter));
                    parent.Items.Add(CreateModuleGroupItem(ModuleGroupsEnum.TargetMarkers, labelConverter));
                    break;
                case ModuleMetaGroupsEnum.ElectronicWarfare:
                    parent.Items.Add(CreateModuleGroupItem(ModuleGroupsEnum.Demobilizers, labelConverter));
                    parent.Items.Add(CreateModuleGroupItem(ModuleGroupsEnum.Eccms, labelConverter));
                    parent.Items.Add(CreateModuleGroupItem(ModuleGroupsEnum.Ecms, labelConverter));
                    parent.Items.Add(CreateModuleGroupItem(ModuleGroupsEnum.InterferenceModules, labelConverter));
                    parent.Items.Add(CreateModuleGroupItem(ModuleGroupsEnum.SapHackingModules, labelConverter));
                    parent.Items.Add(CreateModuleGroupItem(ModuleGroupsEnum.SensorSuppressors, labelConverter));
                    parent.Items.Add(CreateModuleGroupItem(ModuleGroupsEnum.ECMTunings, labelConverter));
                    parent.Items.Add(CreateModuleGroupItem(ModuleGroupsEnum.SensorSuppressorTunings, labelConverter));
                    break;

                case ModuleMetaGroupsEnum.EngineeringEquipment:
                    parent.Items.Add(CreateModuleGroupItem(ModuleGroupsEnum.AccumulatorRechargers, labelConverter));
                    parent.Items.Add(CreateModuleGroupItem(ModuleGroupsEnum.AuxiliaryAccumulators, labelConverter));
                    parent.Items.Add(CreateModuleGroupItem(ModuleGroupsEnum.Coreactors, labelConverter));
                    parent.Items.Add(CreateModuleGroupItem(ModuleGroupsEnum.EnergyDrainers, labelConverter));
                    parent.Items.Add(CreateModuleGroupItem(ModuleGroupsEnum.EnergyInjectors, labelConverter));
                    parent.Items.Add(CreateModuleGroupItem(ModuleGroupsEnum.EnergyNeutralizers, labelConverter));
                    parent.Items.Add(CreateModuleGroupItem(ModuleGroupsEnum.EnergyTransferers, labelConverter));
                    parent.Items.Add(CreateModuleGroupItem(ModuleGroupsEnum.Erp, labelConverter));
                    parent.Items.Add(CreateModuleGroupItem(ModuleGroupsEnum.EvasiveModules, labelConverter));
                    parent.Items.Add(CreateModuleGroupItem(ModuleGroupsEnum.EngineeringTunings, labelConverter));
                    parent.Items.Add(CreateModuleGroupItem(ModuleGroupsEnum.ReactorSealings, labelConverter));
                    break;
                case ModuleMetaGroupsEnum.Industrial:
                    parent.Items.Add(CreateModuleGroupItem(ModuleGroupsEnum.Geoscanners, labelConverter));
                    parent.Items.Add(CreateModuleGroupItem(ModuleGroupsEnum.HarvesterModules, labelConverter));
                    parent.Items.Add(CreateModuleGroupItem(ModuleGroupsEnum.IndustrialTunings, labelConverter));
                    parent.Items.Add(CreateModuleGroupItem(ModuleGroupsEnum.MinerModules, labelConverter));
                    parent.Items.Add(CreateModuleGroupItem(ModuleGroupsEnum.ConstructionModules, labelConverter));
                    parent.Items.Add(CreateModuleGroupItem(ModuleGroupsEnum.TerraformingModules, labelConverter));
                    break;
                case ModuleMetaGroupsEnum.NexusModules:
                    parent.Items.Add(CreateModuleGroupItem(ModuleGroupsEnum.NexusModuleArmor, labelConverter));
                    parent.Items.Add(CreateModuleGroupItem(ModuleGroupsEnum.NexusModuleAssault, labelConverter));
                    parent.Items.Add(CreateModuleGroupItem(ModuleGroupsEnum.NexusModuleCriticalHit, labelConverter));
                    parent.Items.Add(CreateModuleGroupItem(ModuleGroupsEnum.NexusModuleEvasive, labelConverter));
                    parent.Items.Add(CreateModuleGroupItem(ModuleGroupsEnum.NexusModuleEw, labelConverter));
                    parent.Items.Add(CreateModuleGroupItem(ModuleGroupsEnum.NexusModuleFarlock, labelConverter));
                    parent.Items.Add(CreateModuleGroupItem(ModuleGroupsEnum.NexusModuleFastExtractor, labelConverter));
                    parent.Items.Add(CreateModuleGroupItem(ModuleGroupsEnum.NexusModuleIndustrial, labelConverter));
                    parent.Items.Add(CreateModuleGroupItem(ModuleGroupsEnum.NexusModuleLockBooster, labelConverter));
                    parent.Items.Add(CreateModuleGroupItem(ModuleGroupsEnum.NexusModuleRecharger, labelConverter));
                    parent.Items.Add(CreateModuleGroupItem(ModuleGroupsEnum.NexusModuleRepairer, labelConverter));
                    parent.Items.Add(CreateModuleGroupItem(ModuleGroupsEnum.NexusModuleShield, labelConverter));
                    parent.Items.Add(CreateModuleGroupItem(ModuleGroupsEnum.NexusModuleVelocity, labelConverter));
                    break;
                case ModuleMetaGroupsEnum.Shield:
                    parent.Items.Add(CreateModuleGroupItem(ModuleGroupsEnum.ShieldGenerators, labelConverter));
                    parent.Items.Add(CreateModuleGroupItem(ModuleGroupsEnum.ShieldHardeners, labelConverter));
                    break;
                case ModuleMetaGroupsEnum.Weapons:
                    parent.Items.Add(CreateModuleGroupItem(ModuleGroupsEnum.Firearms, labelConverter));
                    parent.Items.Add(CreateModuleGroupItem(ModuleGroupsEnum.Lasers, labelConverter));
                    parent.Items.Add(CreateModuleGroupItem(ModuleGroupsEnum.MagneticWeapons, labelConverter));
                    parent.Items.Add(CreateModuleGroupItem(ModuleGroupsEnum.MissileLaunchers, labelConverter));
                    parent.Items.Add(CreateModuleGroupItem(ModuleGroupsEnum.WeaponTunings, labelConverter));
                    break;
            }
        }

        private TreeViewItem CreateModuleClassItem(string header, string tag = null)
        {
            var item = new TreeViewItem() { Header = header, Tag = tag ?? header };
            item.Items.Add(string.Empty);

            item.Selected += OnModuleTreeViewItemSelected;
            item.Expanded += OnModuleTreeViewItemExpanded;
            item.Collapsed += OnTreeViewItemCollapsed;
            
            return item;
        }

        private void CreateModuleClassItems(ItemsControl parent, ModuleGroupsEnum grp)
        {
            if(parent == null) return;
            switch (grp)
            {
                case ModuleGroupsEnum.ArmorHardeners :
                    parent.Items.Add(CreateModuleClassItem("Chemical"));
                    parent.Items.Add(CreateModuleClassItem("Kinetic"));
                    parent.Items.Add(CreateModuleClassItem("Seismic"));
                    parent.Items.Add(CreateModuleClassItem("Thermal"));
                    parent.Items.Add(CreateModuleClassItem("Universal"));
                    break;

                case ModuleGroupsEnum.Demobilizers:
                    parent.Items.Add(CreateModuleClassItem("Long"));
                    parent.Items.Add(CreateModuleClassItem("Short"));
                    break;

                case ModuleGroupsEnum.Erp:
                    parent.Items.Add(CreateModuleClassItem("Kinetic"));
                    parent.Items.Add(CreateModuleClassItem("Seismic"));
                    parent.Items.Add(CreateModuleClassItem("Thermal"));
                    break;

                case ModuleGroupsEnum.WeaponTunings:
                    parent.Items.Add(CreateModuleClassItem("Firearms"));
                    parent.Items.Add(CreateModuleClassItem("Lasers"));
                    parent.Items.Add(CreateModuleClassItem("Magnetic Weapons", "MagneticWeapons"));
                    parent.Items.Add(CreateModuleClassItem("Missile Launchers", "MissileLaunchers"));
                    parent.Items.Add(CreateModuleClassItem("Weapon Stabilizers", "WeaponStabilizers"));
                    break;

                case ModuleGroupsEnum.ArmorPlates :
                case ModuleGroupsEnum.ArmorRepairers:
                case ModuleGroupsEnum.RemoteArmorRepairers:
                case ModuleGroupsEnum.AuxiliaryAccumulators:
                case ModuleGroupsEnum.EnergyDrainers :
                case ModuleGroupsEnum.EnergyInjectors :
                case ModuleGroupsEnum.EnergyNeutralizers :
                case ModuleGroupsEnum.EnergyTransferers :
                case ModuleGroupsEnum.HarvesterModules :
                case ModuleGroupsEnum.MinerModules :
                case ModuleGroupsEnum.ShieldGenerators :
                case ModuleGroupsEnum.Firearms :
                case ModuleGroupsEnum.Lasers :
                case ModuleGroupsEnum.MagneticWeapons:
                case ModuleGroupsEnum.MissileLaunchers :
                    parent.Items.Add(CreateModuleClassItem("Medium"));
                    parent.Items.Add(CreateModuleClassItem("Small"));
                    break;

                case ModuleGroupsEnum.ArmorRepairersTunings :
                case ModuleGroupsEnum.LightweightFrames:
                case ModuleGroupsEnum.CargoScanners:
                case ModuleGroupsEnum.ChassisScanners:
                case ModuleGroupsEnum.Coprocessors:
                case ModuleGroupsEnum.RangeExtenders:
                case ModuleGroupsEnum.RemoteSensorAmplifiers:
                case ModuleGroupsEnum.SensorAmplifiers:
                case ModuleGroupsEnum.SignalDetectors:
                case ModuleGroupsEnum.SignalMaskers:
                case ModuleGroupsEnum.TargetMarkers:
                case ModuleGroupsEnum.Eccms:
                case ModuleGroupsEnum.Ecms:
                case ModuleGroupsEnum.ECMTunings:
                case ModuleGroupsEnum.SensorSuppressorTunings:
                case ModuleGroupsEnum.InterferenceModules:
                case ModuleGroupsEnum.SapHackingModules:
                case ModuleGroupsEnum.SensorSuppressors:
                case ModuleGroupsEnum.AccumulatorRechargers:
                case ModuleGroupsEnum.Coreactors:
                case ModuleGroupsEnum.EvasiveModules :
                case ModuleGroupsEnum.Geoscanners :
                case ModuleGroupsEnum.IndustrialTunings :
                case ModuleGroupsEnum.NexusModuleArmor:
                case ModuleGroupsEnum.NexusModuleAssault:
                case ModuleGroupsEnum.NexusModuleCriticalHit:
                case ModuleGroupsEnum.NexusModuleEvasive:
                case ModuleGroupsEnum.NexusModuleEw:
                case ModuleGroupsEnum.NexusModuleFarlock:
                case ModuleGroupsEnum.NexusModuleFastExtractor:
                case ModuleGroupsEnum.NexusModuleIndustrial:
                case ModuleGroupsEnum.NexusModuleLockBooster:
                case ModuleGroupsEnum.NexusModuleRecharger:
                case ModuleGroupsEnum.NexusModuleRepairer:
                case ModuleGroupsEnum.NexusModuleShield:
                case ModuleGroupsEnum.NexusModuleVelocity:
                case ModuleGroupsEnum.ShieldHardeners :
                case ModuleGroupsEnum.EngineeringTunings:
                case ModuleGroupsEnum.ReactorSealings:
                case ModuleGroupsEnum.ConstructionModules:
                case ModuleGroupsEnum.TerraformingModules:


                    // Add modules
                    var meta = (ModuleMetaGroupsEnum)((TreeViewItem)parent.Parent).Tag;
                    Task.Factory.StartNew(() =>
                                Dispatcher.Invoke(
                                    new ActionDelegate(() =>
                                                {
                                                    foreach (var module in Repository.Default.Modules.Where( m => m.MetaGroup == meta && m.Group == grp))
                                                        parent.Items.Add(CreateModuleTreeViewItem(module));
                                                })));
                    break;
            }
        }

        private TreeViewItem CreateModuleTreeViewItem(IModule module)
        {
            var item = new TreeViewItem()
                           {
                               Header = module.Name,
                               DataContext = module,
                               Template = _moduleTreeviewItemTemplate,
                           };

            item.MouseDoubleClick += OnModuleItemMouseDoubleClick;
            item.Selected += OnModuleSelected;

            return item;
        }

        private void OnRobotsTreeViewItemSelected(object sender, RoutedEventArgs e)
        {
            e.Handled = true;
            _robotViewLevel = RobotViewLevel.Default;

            Task.Factory.StartNew(
                        () => SetRobotsList(Repository.Default.Robots),
                        CancellationToken.None,
                        TaskCreationOptions.None,
                        TaskScheduler.FromCurrentSynchronizationContext());

            
        }

        private void OnRobotsTreeViewItemExpanded(object sender, RoutedEventArgs e)
        {
            e.Handled = true;
            _robotViewLevel = RobotViewLevel.Default;
            var item = e.Source as TreeViewItem;
            if (item == null) return;

            Task.Factory.StartNew(
                        () =>
                        {
                            item.Items.Clear();

                            foreach (var faction in Repository.Default.Robots.Select(r => r.Faction).Distinct())
                                item.Items.Add(CreateRobotFactionTreeViewItem(faction));
                        },
                        CancellationToken.None,
                        TaskCreationOptions.None,
                        TaskScheduler.FromCurrentSynchronizationContext());

            
        }

        private void OnRobotFactionTreeViewItemExpanded(object sender, RoutedEventArgs e)
        {
            e.Handled = true;
            _robotViewLevel = RobotViewLevel.Faction;
            var item = e.Source as TreeViewItem;
            if (item == null) return;


            Task.Factory.StartNew(
                        () =>
                        {
                            item.Items.Clear();

                            var faction = (FactionsEnum)item.Tag;

                            foreach (var robotSize in Repository.Default.Robots.Where(r => r.Faction == faction).Select(r => r.Size).Distinct())
                                item.Items.Add(CreateRobotSizeTreeViewItem(robotSize));
                        },
                        CancellationToken.None,
                        TaskCreationOptions.None,
                        TaskScheduler.FromCurrentSynchronizationContext());

           

        }

        private void OnRobotFactionTreeViewItemSelected(object sender, RoutedEventArgs e)
        {
            e.Handled = true;
            _robotViewLevel = RobotViewLevel.Faction;
            var item = e.Source as TreeViewItem;
            if (item == null) return;

            var faction = (FactionsEnum)item.Tag;

            Task.Factory.StartNew(
                        () => SetRobotsList(Repository.Default.Robots.Where(r => r.Faction == faction)),
                        CancellationToken.None,
                        TaskCreationOptions.None,
                        TaskScheduler.FromCurrentSynchronizationContext());
        }

        private void OnRobotSizeTreeViewItemExpanded(object sender, RoutedEventArgs e)
        {
            e.Handled = true;
            _robotViewLevel = RobotViewLevel.Size;
            var item = e.Source as TreeViewItem;
            if (item == null) return;

            var faction = (FactionsEnum) ((TreeViewItem) item.Parent).Tag;
            var size = (RobotSizesEnum) item.Tag;

            Task.Factory.StartNew(
                () =>
                    {
                        item.Items.Clear();
                        foreach (
                            var robot in Repository.Default.Robots.Where(r => r.Faction == faction && r.Size == size))
                            item.Items.Add(CreateRobotTreeViewItem(robot));
                    },
                CancellationToken.None,
                TaskCreationOptions.None,
                TaskScheduler.FromCurrentSynchronizationContext());


        }

        private void OnRobotSizeTreeViewItemSelected(object sender, RoutedEventArgs e)
        {
            e.Handled = true;
            _robotViewLevel = RobotViewLevel.Size;
            var item = e.Source as TreeViewItem;
            if (item == null) return;

            var faction = (FactionsEnum) ((TreeViewItem) item.Parent).Tag;
            var size = (RobotSizesEnum) item.Tag;

            Task.Factory.StartNew(
                        () => SetRobotsList(Repository.Default.Robots.Where(r => r.Faction == faction && r.Size == size)),
                        CancellationToken.None,
                        TaskCreationOptions.None,
                        TaskScheduler.FromCurrentSynchronizationContext());
        }

        private TreeViewItem CreateRobotFactionTreeViewItem(FactionsEnum faction)
        {
            var item =  new TreeViewItem()
                {
                    Header = faction,
                    Tag = faction
                };

            item.Items.Add(string.Empty);
            item.Expanded += OnRobotFactionTreeViewItemExpanded;
            item.Collapsed += OnTreeViewItemCollapsed;
            item.Selected += OnRobotFactionTreeViewItemSelected;

            return item;
        }

        private TreeViewItem CreateRobotSizeTreeViewItem(RobotSizesEnum size)
        {
            var item = new TreeViewItem()
            {
                Header = size,
                Tag = size
            };

            item.Items.Add(string.Empty);
            item.Expanded += OnRobotSizeTreeViewItemExpanded;
            item.Collapsed += OnTreeViewItemCollapsed;
            item.Selected += OnRobotSizeTreeViewItemSelected;

            return item;
        }

        private TreeViewItem CreateRobotTreeViewItem(IRobot robot)
        {
            var item = new TreeViewItem()
                {
                    Header = robot.Name,
                    Template = _robotTreeviewItemTemplate ,
                    DataContext = robot
                };

            item.MouseRightButtonDown += OnRobotTreeViewItemMouseRightButtonDown;
            item.MouseDoubleClick += OnRobotItemMouseDoubleClick;
            item.Selected += OnRobotTreeViewItemSelected;
            return item;
        }

        private static void OnRobotTreeViewItemMouseRightButtonDown(object sender, MouseButtonEventArgs e)
        {
            e.Handled = true;
            var tvitem = e.Source as TreeViewItem;
            if (tvitem == null) return;
            
            if(!tvitem.IsSelected)
                tvitem.IsSelected = true;
        }

        private void OnRobotTreeViewItemSelected(object sender, RoutedEventArgs e)
        {
            e.Handled = true;
            var item = e.Source as TreeViewItem;
            if (item == null || item.ContextMenu != null) return;

            var ctx = new ContextMenu();
            ctx.Items.Add(new MenuItem()
            {
                CommandParameter = ((IRobot)item.DataContext).Name,
                Header = string.Format(Messages.menu_new_bot_fitting, (IRobot)item.DataContext),
            });

            ctx.Opened += OnRobotItemContextMenuOpened;
            item.ContextMenu = ctx;
        }

        private void OnRobotItemMouseDoubleClick(object sender, MouseButtonEventArgs e)
        {
            e.Handled = true;
            if (NewFittingCommand == null) return;
            var item = sender as TreeViewItem;
            if (item == null || item.DataContext == null) return;
            var bot = item.DataContext as IRobot;
            if (bot == null) return;

            NewFittingCommand.Execute(bot.Name);
        }

        private void OnRobotItemContextMenuOpened(object sender, RoutedEventArgs e)
        {
            e.Handled = true;
            var mnuItem = ((MenuItem)((ContextMenu)e.Source).Items[0]);
            if (mnuItem.Command == null)
                mnuItem.Command = NewFittingCommand;
        }

        private static void OnTreeViewItemCollapsed(object sender, RoutedEventArgs e)
        {
            e.Handled = true;
            ClearTreeViewItems(e.Source as TreeViewItem);
        }

        private void OnModuleItemMouseDoubleClick(object sender, MouseButtonEventArgs e)
        {
            e.Handled = true;
            if (AddModuleCommand == null) return;

            var item = sender as TreeViewItem;
            if (item == null || item.DataContext == null) return;

            if(item.DataContext is IModule)
                AddModuleCommand.Execute(item.DataContext);
        }

        private static void ClearTreeViewItems(ItemsControl item)
        {
            if(item == null) return;
            item.Items.Clear();
            item.Items.Add(string.Empty);
        }
        
        private static void OnModuleSelected(object sender, RoutedEventArgs e)
        {
            e.Handled = true;
        }

        private void SetRobotsList(IEnumerable<IRobot> robots)
        {
            using (_robotsViewSource.DeferRefresh())
            {
                _robotsViewSource.GroupDescriptions.Clear();

                if (robots != null)
                    switch (_robotViewLevel)
                    {
                        case RobotViewLevel.Default:
                            _robotsViewSource.GroupDescriptions.Add(new PropertyGroupDescription("Faction"));
                            break;
                        case RobotViewLevel.Faction:
                            _robotsViewSource.GroupDescriptions.Add(new PropertyGroupDescription("Size"));
                            break;
                    }

                _robotsViewSource.Source = robots;
                _modulesViewSource.Source = null;
            }

            itemsListview.View = _robotsGridView;
            itemsListview.ItemsSource = _robotsViewSource.View;
        }

        private void SetModulesList(IEnumerable<IModule> modules)
        {
            if (!Dispatcher.CheckAccess())
                Dispatcher.Invoke(new ActionDelegate<IEnumerable<IModule>>(SetModulesList), modules);
            else
            {
                using (_modulesViewSource.DeferRefresh())
                {
                    _modulesViewSource.GroupDescriptions.Clear();

                    if (modules != null)
                        switch (_moduleViewLevel)
                        {
                            case ModuleViewLevel.Default:
                                _modulesViewSource.GroupDescriptions.Add(new PropertyGroupDescription("MetaGroup", new ModuleMetagroupsToLabelConverter()));
                                break;
                            case ModuleViewLevel.MetaGroup:
                                _modulesViewSource.GroupDescriptions.Add(new PropertyGroupDescription("Group", new ModuleGroupsToLabelConverter()));
                                break;
                            case ModuleViewLevel.Group:
                                _modulesViewSource.GroupDescriptions.Add(new PropertyGroupDescription("Size"));
                                break;
                        }

                    _modulesViewSource.Source = modules;
                    _robotsViewSource.Source = null;
                }

                itemsListview.View = _modulesGridView;
                itemsListview.ItemsSource = _modulesViewSource.View;
            }
        }

        private void SortListViewItems(string sortBy, ListSortDirection direction)
        {
            var dataView = CollectionViewSource.GetDefaultView(itemsListview.ItemsSource);
            dataView.SortDescriptions.Clear();
            dataView.SortDescriptions.Add(new SortDescription(sortBy, direction));
            dataView.Refresh();
        }

        private void GridViewColumnHeader_Click(object sender, RoutedEventArgs e)
        {
            e.Handled = true;

            if (itemsListview.IsGrouping) return;

            var headerClicked = e.OriginalSource as GridViewColumnHeader;
            if (headerClicked == null || headerClicked.Role == GridViewColumnHeaderRole.Padding) return;

            ListSortDirection direction;
            if (headerClicked != _lastHeaderClicked)
            {
                direction = ListSortDirection.Ascending;
            }
            else
            {
                direction = _lastDirection == ListSortDirection.Ascending ? ListSortDirection.Descending : ListSortDirection.Ascending;
            }

            var header = headerClicked.Column.DisplayMemberBinding == null
                ? "TechnologyLevel" // Handles module Tech level image sorting...
                : ((Binding)headerClicked.Column.DisplayMemberBinding).Path.Path;

            SortListViewItems(header, direction);

            _lastHeaderClicked = headerClicked;
            _lastDirection = direction;
        }

        private void ListViewItem_MouseDoubleClick(object sender, MouseButtonEventArgs e)
        {
            e.Handled = true;
            var item = sender as ListViewItem;
            if (item == null || item.DataContext == null) return;

            if (AddModuleCommand != null && item.DataContext is IModule)
            {
                AddModuleCommand.Execute(item.DataContext);
            }
            else if (NewFittingCommand != null && item.DataContext is IRobot)
            {
                NewFittingCommand.Execute(((IRobot)item.DataContext).Name);
            }
        }
    }
}
